#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <unordered_map>
#include "Session.hpp"


//默认参数
const std::string seq = "\r\n"; 
const std::string seqline = " ";
const std::string HeaderLineSep = ": ";
const std::string urlseq = "?";
const std::string format = ".";
const std::string gdefaultpath = "./wwwroot";
const std::string http__versions = "HTTP/1.0";
const std::string page404 = "./wwwroot/404.html";
const std::string firstpage = "index.html";
SessionManager sm;

bool ExtractHead(std::string &in, std::string *out, const std::string &seq)
{
    auto pos = in.find(seq);
    if (pos == std::string::npos)
    {
        return false;
    }

    *out = in.substr(0, pos);
    in.erase(0, pos + seq.size());

    if (out->empty())
    {
        return false;
    }

    return true;
}

// 请求
class HttpRequest
{

private:
    void _ExtractHeadValKV()
    {
        for (auto e : _headval)
        {
            auto pos = e.find(HeaderLineSep);
            if (pos == std::string::npos)
                continue;

            _headvalkv[e.substr(0, pos)] = e.substr(pos + HeaderLineSep.size());
        }
    }

public:
    HttpRequest() = default;
    ~HttpRequest() = default;
    /*
    GET / HTTP/1.1/r/n
    Host: 124.71.223.168:8989
    Connection: keep-alive
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36 Edg/132.0.0.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,
    */

    void ExtractHeadVal(std::string &in, const std::string &seq)
    {
        std::string val;
        while (ExtractHead(in, &val, seq))
        {
            _headval.push_back(val);
        }

        // 对 _headval 再进行分割
        _ExtractHeadValKV();
    }

    bool ExtractHeadLine(const std::string &in, const std::string &seq)
    {
        std::stringstream ss(in);
        ss >> _method >> _url >> _versions;

        std::cout << _method << std::endl;
        std::cout << _url << std::endl;
        std::cout << _versions << std::endl;

        return true;
    }

    bool Isexec()
    {
        return _isexec;
    }

    void ExtractUrl()
    {
        if (_method == "POST")
        {
            _isexec = true;
            _path = _url;
            _args = _data;
        }
        else if (_method == "GET")
        {
            auto pos = _url.find(urlseq);
            if (pos != std::string::npos)
            {
                _isexec = true;
                _path = _url.substr(0, pos);
                _args = _url.substr(pos + urlseq.size());
            }
        }
    }

    void Deserialization(std::string &in)
    {
        // 拿出头部
        if (ExtractHead(in, &_headline, seq))
        {
            std::cout << "_headline" << _headline << std::endl;

            // 对第一行再进行分析
            ExtractHeadLine(_headline, seqline);

            // 将剩下的头部拿出
            ExtractHeadVal(in, seq);

            // 空行
            _nullline = seq;

            // 内容
            _data = in;

            // 对_url进行解析
            ExtractUrl();
        }
    }

    std::string GetContent(const std::string path)
    {
        std::string content;

        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
        {
            return std::string();
        }

        in.seekg(0, in.end);
        int len = in.tellg();
        in.seekg(0, in.beg);
        content.resize(len);
        in.read((char *)content.c_str(), len);

        in.close();

        return content;
    }

    void Print()
    {
        std::cout << "_headline:" << _headline << std::endl;
        std::cout << "_method:" << _method << std::endl;
        std::cout << "_url:" << _url << std::endl;
        std::cout << "_versions:" << _versions << std::endl;
        std::cout << "--------------------------------------" << std::endl;
        for (auto e : _headval)
        {
            std::cout << e << std::endl;
        }
        std::cout << "--------------------------------------" << std::endl;

        std::cout << "--------------------------------------" << std::endl;
        for (auto [a, b] : _headvalkv)
        {
            std::cout << a << std::endl;
            std::cout << b << std::endl;
        }
        std::cout << "--------------------------------------" << std::endl;

        std::cout << "_data:" << _data << std::endl;
    }

    std::string GetUrl()
    {
        return _url;
    }

    std::string GetVersions()
    {
        return _versions;
    }

    std::string GetData()
    {
        return _data;
    }

    std::string GetMethod()
    {
        return _method;
    }

    std::string GetHeadvalkv(const std::string k)
    {
        if (_headvalkv.find(k) == _headvalkv.end())
            return std::string();

        return _headvalkv[k];
    }

    std::string GetPath()
    {
        return _path;
    }

    std::string GetArgs()
    {
        return _args;
    }

    void SetUrl(const std::string &url)
    {
        _url = url;
    }

private:
    std::string _headline;             // 报头第一行
    std::vector<std::string> _headval; // 报头除第一行的其他行
    std::string _nullline;             // 空行
    std::string _data;                 // 有效内容

    std::string _url;
    std::string _method;                                     // 方法
    std::string _versions;                                   // 版本
    std::unordered_map<std::string, std::string> _headvalkv; // 报头除第一行的其他行kv

    std::string _args;    // 第一行参数
    std::string _path;    // 纯路径
    bool _isexec = false; // 是否带参数
};

// 应答
class HttpResponse
{
public:
    HttpResponse(std::string versions = http__versions)
        : _versions(http__versions)
    {
    }
    ~HttpResponse() = default;

    // 构建应答
    void Build(HttpRequest &req)
    {
        std::string url = req.GetUrl();

        url = gdefaultpath + url;
        if (url.back() == '/')
        {
            url += firstpage;
        }

        std::string id = req.GetHeadvalkv("Cookie");
        if (!id.empty())
        {
            auto pos = id.find("=");
            id = id.substr(pos+1);
            session_ptr sp = sm.GetSession(id);
            if(sp == nullptr)
                std::cout<<"不存在id:"<<id<<std::endl;
            else
                std::cout<<"登录成功："<<"id:"<<id<<"name:"<<sp->GetName()<<"p:"<<sp->GetPassword()<<std::endl;
        }

        // 读取文件
        _data = req.GetContent(url);

        // 设置状态码和状态描述
        if (_data.empty())
        {
            url = page404;
            _data = req.GetContent(url);
            _code = 404;
        }
        else
        {
            _code = 200;
        }
        _code_describe = Code2Desc(_code);

        // 设置文件格式属性
        auto pos = url.rfind(format);
        std::string suffix = url.substr(pos);
        SetHeadValKV("Content-Type", Suffix2Desc(suffix));
        // 设置长度属性
        SetHeadValKV("Content-Length", std::to_string(_data.size()));
    }

    // 序列化
    void Serialize(std::string *resp_str)
    {
        std::string res;
        res = _versions + seqline + std::to_string(_code) + seqline + _code_describe + seq;

        for (auto [k, v] : _headvalkv)
        {
            std::string tmp = k + HeaderLineSep + v + seq;
            res += tmp;
        }

        res += _nullline;
        res += _data;

        *resp_str = res;
    }

    void SetData(const std::string &data)
    {
        _data = data;
    }

    void SetCode(const int code)
    {
        _code = code;
        _code_describe = Code2Desc(_code);
    }

    // 设置属性
    void SetHeadValKV(const std::string k, const std::string v)
    {
        _headvalkv[k] = v;
    }

private:
    // 状态码与状态转换
    std::string Code2Desc(int code)
    {
        switch (code)
        {
        case 200:
            return "OK";
        case 404:
            return "Not Found";
        case 301:
            return "Moved Permanently";
        case 302:
            return "Found";
        default:
            return std::string();
        }
    }

    // 文件格式转换
    std::string Suffix2Desc(const std::string &suffix)
    {
        if (suffix == ".html")
            return "text/html";
        else if (suffix == ".jpg")
            return "application/x-jpg";
        else
            return "text/html";
    }

    void Print()
    {
        std::cout << "_versions:" << _versions << std::endl;
        std::cout << "_code:" << _code << std::endl;
        std::cout << "_code_describe:" << _code_describe << std::endl;
        std::cout << "_data:" << _data << std::endl;
    }

private:
    std::string _data;           // 正文
    std::string _nullline = seq; // 空行

    std::string _versions;                                   // 版本
    int _code;                                               // 状态码
    std::string _code_describe;                              // 状态码描述
    std::unordered_map<std::string, std::string> _headvalkv; // 除第一行的其他头部
};
